package gao.xiaolei.service;

import gao.xiaolei.dao.*;
import gao.xiaolei.dto.*;
import gao.xiaolei.entity.*;
import gao.xiaolei.util.ServiceName;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import gao.xiaolei.exception.AuthException;
import gao.xiaolei.util.RedisUtil;
import gao.xiaolei.util.UuidUtil;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

@Service("ClassesService")
public class ClassesService {
    @Resource(name = "ClassesDao")
    private ClassesDao classesDao;

    @Resource(name = "ClassesProcessDao")
    private ClassesProcessDao classesProcessDao;

    @Resource(name = "ClassesProcessViewDao")
    private ClassesProcessViewDao classesProcessViewDao;

    @Resource(name = "GroupClassesDao")
    private GroupClassesDao groupClassesDao;

    @Resource(name = "GroupMemberDao")
    private GroupMemberDao groupMemberDao;

    @Resource(name = "UserClassesDao")
    private UserClassesDao userClassesDao;

    @Resource(name = "UserDao")
    private UserDao userDao;

    @Resource(name = "RoleDao")
    private RoleDao roleDao;

    @Resource(name = "GroupDao")
    private GroupDao groupDao;

    @Resource(name = "GroupService")
    private GroupService groupService;

    @Resource(name = "AuthVersionDao")
    private AuthVersionDao authVersionDao;

    @Resource(name = "UserRoleDao")
    private UserRoleDao userRoleDao;

    @Resource(name = "RedisUtil")
    private RedisUtil redis;

    @Autowired
    private RestTemplate restTemplate;

    @Resource(name = "ClassesGroupUserViewDao")
    private ClassesGroupUserViewDao classesGroupUserViewDao;

    @Transactional(readOnly = true)
    //获取根据负责人获取班级的列表（树形结构）
    public List<TreeDto> getRootClassesByLeader(String leader) {
        List<Object[]> classList = classesDao.findByLeader(leader);
        return objectToClassesDto(classList);
    }

    @Transactional(readOnly = true)
    //获取根据创建人获取班级的列表（树形结构）
    public List<TreeDto> getRootClassesByCreater(String creater) {
        List<Object[]> classList = classesDao.findByCreater(creater);
        return objectToClassesDto(classList);
    }

    @Transactional(readOnly = true)
    //获取用户所属的班级列表（树形结构）
    public List<TreeDto> getRootClassesByUserIn(String userId) {
        List<String> classesIds = userClassesDao.getClassIdsByUserId(userId);
        List<Classes> classesList = classesDao.findAllById(classesIds);
        List<TreeDto> result = new ArrayList<>(classesList.size());
        ClassesGroupUserView viewExample = new ClassesGroupUserView(userId);
        for (int i = 0, length = classesList.size(); i < length; i++) {
            Classes classes = classesList.get(i);
            viewExample.setClassesId(classes.getId());
            int childrenCount = (int) classesGroupUserViewDao.count(Example.of(viewExample));//去视图里查找用户属于该班级下组的数量
            result.add(new TreeDto(classes.getId(), "root", 0, childrenCount, classes.getName()));
        }
        return result;
    }


    @Transactional(readOnly = true)
    //获取班级详细信息
    public ClassesDto getClassesDetail(String id) {
        Classes classes = classesDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该班级("
                .concat(id)
                .concat(")不存在！")));
        String createrName = userDao.getRealName(classes.getCreater());
        String leaderName = userDao.getRealName(classes.getLeader());
        List<ClassesMemberDto> members = getClassesMember(id);
        return new ClassesDto(classes, createrName, leaderName, members);
    }

    @Transactional
    //添加班级
    public void addClasses(ClassesInDto classesInDto, boolean isAutomatic) {
        classesDao.save(new Classes(classesInDto.getId(), classesInDto.getName(), classesDao.getMaxStage().orElse(0) + 1, classesInDto.getCreater(), classesInDto.getLeader(), LocalDateTime.now(), classesInDto.getDescribe(), isAutomatic));
        List<String> classesMember = classesInDto.getClassesMember();
        for (int i = 0, length = classesMember.size(); i < length; i++) {//保存班级人员信息
            userClassesDao.save(new UserClass(UuidUtil.get32Uuid(), classesInDto.getId(), classesMember.get(i)));
        }
    }

    @Transactional
    //修改班级
    public void updateClasses(ClassesInDto classesInDto) {
        Classes oldClasses = classesDao.findById(classesInDto.getId()).orElseThrow(() -> new IllegalArgumentException("该班级（"
                .concat(classesInDto.getId())
                .concat(")不存在！")));
        if (!oldClasses.getCreater().equals(classesInDto.getCurrentUserId()))
            throw new AuthException("你无权修改该班级(".concat(classesInDto.getId()).concat(")"));
        List<String> oldMemberId = userClassesDao.getUserIdsByClassId(classesInDto.getId());//先找出该班级原来的成员列表
        List<String> willDeleteMember = new LinkedList<>();//记录哪些成员要被删除
        List<String> newClassesMember = classesInDto.getClassesMember();
        int i, j, length, length2;
        boolean isDelete;
        for (i = 0, length = oldMemberId.size(); i < length; i++) {
            isDelete = true;
            for (j = 0, length2 = newClassesMember.size(); j < length2; j++) {
                if (oldMemberId.get(i).equals(newClassesMember.get(j))) {
                    isDelete = false;
                    break;
                }
            }
            if (isDelete)
                willDeleteMember.add(oldMemberId.get(i));
        }
        List<String> groupIds = groupClassesDao.findGroupIdByClassId(classesInDto.getId());//再把该班级下的组找出来
        for (i = 0, length = willDeleteMember.size(); i < length; i++) {//然后去删除这些要删除的人与这些组的关系
            for (j = 0, length2 = groupIds.size(); j < length2; j++) {
                GroupMemberId groupMemberId = new GroupMemberId(groupIds.get(j), willDeleteMember.get(i));
                groupMemberDao.findById(groupMemberId).ifPresent(groupMember -> {//删除前先看一下存不存在,不然就会报EmptyResultDataAccessException
                    if (groupMember.getIsLeader() == 1) {//如果他是组长的话
                        int leadGroupCount = groupMemberDao.getLeadGroupCount(groupMember.getId().getUserId());//先要查看一下他现在是几个组的组长
                        if (leadGroupCount <= 1)//如果现在不是一个以上组的组长的话,说明把他卸任以后就不是组长的身份了
                            replaceUserRole(groupMember.getId().getUserId(), "ROLE_USER");//就要去把他的角色降低到普通用户角色
                        refreshUserAuthVersionCache(groupMember.getId().getUserId()); //更改了某个人的是组长的组列表，所以要将权限版本号变更
                    }
                    groupMemberDao.deleteById(groupMemberId);//然后再把这些人与这些组的关系删除掉
                });
            }
        }
        classesDao.save(new Classes(classesInDto.getId(), classesInDto.getName(), oldClasses.getStage(), oldClasses.getCreater(), classesInDto.getLeader(), oldClasses.getCreateDate(), classesInDto.getDescribe(), false));
        userClassesDao.deleteAllByClassId(classesInDto.getId());//先将原有的班级成员信息删除
        for (i = 0, length = newClassesMember.size(); i < length; i++) {//保存班级人员信息
            userClassesDao.save(new UserClass(UuidUtil.get32Uuid(), classesInDto.getId(), newClassesMember.get(i)));
        }
    }

    @Transactional
    //删除班级
    public void deleteClasses(String id, String currentUserId) {
        Classes oldClasses = classesDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该班级（"
                .concat(id)
                .concat(")不存在！")));
        if (!oldClasses.getCreater().equals(currentUserId))
            throw new AuthException("你无权修改该班级(".concat(id).concat(")"));
        classesDao.deleteById(id);//删除班级本身信息
        userClassesDao.deleteAllByClassId(id);//删除该班级的成员信息
        List<String> groupIds = groupClassesDao.findGroupIdByClassId(id);//找到该班级下的组
        for (int i = 0, length = groupIds.size(); i < length; i++) {//删除所有组
            groupService.deleteClassesGroup(groupIds.get(i));
        }
    }

    //获取某个班级下的用户列表
    @Transactional(readOnly = true)
    public List<ClassesMemberDto> getClassesMember(String classId) {
        List<String> userIds = userClassesDao.getUserIdsByClassId(classId);//找出该班级下面的用户Id
        List<String> groupIds = groupClassesDao.findGroupIdByClassId(classId);//找出该班级下面的组Id
        List<GroupMemberId> groupMemberIds = new ArrayList<>(groupIds.size());//构建用于去groupMember表查询的id类
        List<ClassesMemberDto> members = new ArrayList<>(userIds.size());
        int i, j, k, length, length2, length3;
        for (i = 0, length = groupIds.size(); i < length; i++) {//将组Id填充进去
            groupMemberIds.add(new GroupMemberId(groupIds.get(i), null));
        }
        for (i = 0, length = userIds.size(); i < length; i++) {
            for (j = 0, length2 = groupMemberIds.size(); j < length2; j++) {
                groupMemberIds.get(j).setUserId(userIds.get(i));//将用户Id填充进去
            }
            List<GroupMember> groupMember = groupMemberDao.findAllByIdIn(groupMemberIds);//根据组装好的条件去查询该用户是属于该班级的哪几个组的
            String userName = userDao.getRealName(userIds.get(i));
            StringBuilder groupNames = new StringBuilder();
            String groupName = null;
            for (k = 0, length3 = groupMember.size(); k < length3; k++) {//获取这个人在这个班所属所有组的组名来拼接
                groupNames.append("、").append(groupDao.getGroupName(groupMember.get(k).getId().getGroupId()));
            }
            groupName = groupNames.length() == 0 ? "无" : groupNames.deleteCharAt(0).toString();
            members.add(new ClassesMemberDto(userIds.get(i), userName, classId, groupName));
        }
        return members;
    }

    //获取某个用户在该班级是属于哪几个组的
    @Transactional(readOnly = true)
    public List<String> getUserInClassesInWitchGroup(String classesId, String userId) {
        List<String> classesGroupIds = groupClassesDao.findGroupIdByClassId(classesId);//找出该班级下面的组Id
        List<GroupMemberId> groupMemberIds = new ArrayList<>(classesGroupIds.size());//构建用于去groupMember表查询的id类
        int i, length;
        for (i = 0, length = classesGroupIds.size(); i < length; i++) {//将组Id和用户Id填充进去
            groupMemberIds.add(new GroupMemberId(classesGroupIds.get(i), userId));
        }
        List<GroupMember> groupMember = groupMemberDao.findAllByIdIn(groupMemberIds);//根据组装好的条件去查询该用户是属于该班级的哪几个组的
        List<String> groupIds = new ArrayList<>(groupMember.size());
        for (i = 0, length = groupMember.size(); i < length; i++) {
            groupIds.add(groupMember.get(i).getId().getGroupId());
        }
        return groupIds;
    }

    //管理员查看班级列表
    @Transactional(readOnly = true)
    public List<ClassesListDto> getClassesListForAdmin(String creater) {
        List<Object[]> classes = classesDao.findByCreater(creater);
        List<ClassesListDto> result = new ArrayList<>(classes.size());
        LocalDateTime nowTime = LocalDateTime.now();
        String id = null, status = null, name = null;
        ClassesProcess process = null;
        for (int i = 0, length = classes.size(); i < length; i++) {
            id = (String) classes.get(i)[0];
            name = (String) classes.get(i)[1];
            process = classesProcessDao.findByToClasses(id);
            if (process.getEnterBeginTime().isAfter(nowTime))
                status = "等待报名开始";
            else {
                if (process.getEnterEndTime().isAfter(nowTime))
                    status = "报名进行中";
                else
                    status = "不满足开班条件(人数:"
                            .concat(userClassesDao.countAllByClassId(id).toString())
                            .concat("/")
                            .concat(process.getMinMemberCount().toString())
                            .concat(")");
            }
            result.add(new ClassesListDto(id, name, status));
        }
        return result;
    }

    //管理员查看班级详情
    @Transactional(readOnly = true)
    public ClassesAndProcessOutDto getClassesDetailForAdmin(String id) {
        Classes classes = classesDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该班级("
                .concat(id)
                .concat(")不存在！")));
        ClassesProcess process = classesProcessDao.findByToClasses(id);
        process.setToDirectorName(userDao.getRealName(process.getToDirector()));
        List<String> classesMember = userClassesDao.getUserIdsByClassId(id);
        List<ClassesMemberDto> memberDtos = new ArrayList<>(classesMember.size());
        for (int i = 0, length = classesMember.size(); i < length; i++) {
            memberDtos.add(new ClassesMemberDto(classesMember.get(i), userDao.getRealName(classesMember.get(i)), null, null));
        }
        return new ClassesAndProcessOutDto(classes, userDao.getRealName(classes.getCreater()), null, memberDtos, process);
    }

    //管理员创建班级
    @Transactional
    public void addClassesForAdmin(ClassesAndProcessInDto classesAndProcessInDto) {
        addClasses(classesAndProcessInDto, !classesAndProcessInDto.isManual());//保存班级基本信息
        ClassesProcess process = classesAndProcessInDto.getProcess();
        if (classesAndProcessInDto.isManual() || classesAndProcessInDto.getClassesMember().size() >= classesAndProcessInDto.getProcess().getMaxMemberCount()) {//如果是手动直接开班的话,或者人数本身已经到达上限的话
            classesDao.updateCreater(process.getToDirector(), classesAndProcessInDto.getId());
            noticeDirectorManageClasses(process.getToDirector(), classesAndProcessInDto.getName());//发送任务通知主任该班级归他管
        } else {
            classesProcessDao.save(process);//保存班级报名流程
            createOpenClassesJob(classesAndProcessInDto);
        }
    }


    //管理员修改班级
    @Transactional
    public void updateClassesForAdmin(ClassesAndProcessInDto classesAndProcessInDto) {
        Classes oldClasses = classesDao.findById(classesAndProcessInDto.getId()).orElseThrow(() -> new IllegalArgumentException("该班级("
                .concat(classesAndProcessInDto.getId())
                .concat(")不存在！")));
        if (!oldClasses.getCreater().equals(classesAndProcessInDto.getCurrentUserId()))
            throw new AuthException("该班级的创建人是:"
                    .concat(oldClasses.getCreater())
                    .concat(",你(")
                    .concat(classesAndProcessInDto.getCurrentUserId())
                    .concat(")无权修改！"));
        ClassesProcess newProcess = classesAndProcessInDto.getProcess();
        List<String> newClassesMember = classesAndProcessInDto.getClassesMember();
        classesDao.save(new Classes(classesAndProcessInDto.getId(), classesAndProcessInDto.getName(), oldClasses.getStage(), oldClasses.getCreater(), oldClasses.getLeader(), oldClasses.getCreateDate(), classesAndProcessInDto.getDescribe(), !classesAndProcessInDto.isManual()));
        userClassesDao.deleteAllByClassId(newProcess.getToClasses());//删除原有班级人员信息
        for (int i = 0, length = newClassesMember.size(); i < length; i++) {//保存新班级人员信息
            userClassesDao.save(new UserClass(UuidUtil.get32Uuid(), newProcess.getToClasses(), newClassesMember.get(i)));
        }
        if (classesAndProcessInDto.isManual()) {//如果是手动直接开班的话
            classesDao.updateCreater(newProcess.getToDirector(), classesAndProcessInDto.getId());//更新班级的创建人
            classesDao.updateIsAutomatic(false, classesAndProcessInDto.getId());//更新班级的判断位，这样就不会出现在用户选择班级的列表上
            noticeDirectorManageClasses(newProcess.getToDirector(), classesAndProcessInDto.getName());//发送任务通知主任该班级归他管
            cancelTimingJob(newProcess.getToClasses(), "openClasses", 0);//取消原有定时任务
        } else {
            ClassesProcess oldProcess = classesProcessDao.findByToClasses(newProcess.getToClasses());
            boolean isChange = !oldProcess.getEnterEndTime().equals(newProcess.getEnterEndTime());
            classesProcessDao.save(newProcess);//保存新的班级流程
            if (newClassesMember.size() >= newProcess.getMaxMemberCount()) {//如果新的班级人数大于等于规定的班级最大人数的话就自动结束开班
                String oldCreater = oldClasses.getCreater();
                classesDao.updateCreater(newProcess.getToDirector(), newProcess.getToClasses());//将此班级的创建人改为预定的主任
                noticeDirectorManageClasses(newProcess.getToDirector(), classesAndProcessInDto.getName());//发送任务通知主任该班级归他管
                noticeAdminClassesCreaterIsChange(newProcess.getToDirector(), oldCreater, classesAndProcessInDto.getName());//发送任务通知管理员班级开班流程结束了
                cancelTimingJob(newProcess.getToClasses(), "openClasses", 0);//取消原有定时任务
                return;
            }
            if (isChange) {//如果修改了结束时间的话就要去修改定时任务
                cancelTimingJob(newProcess.getToClasses(), "openClasses", 0);//取消原有定时任务
                createOpenClassesJob(classesAndProcessInDto);
            }
        }
    }

    @Transactional
    //管理员删除班级
    public void deleteClassesForAdmin(List<String> classesIds, String currentUserId) {
        for (int i = 0, length = classesIds.size(); i < length; i++) {
            String id = classesIds.get(i);
            Classes oldClasses = classesDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该班级("
                    .concat(id)
                    .concat(")不存在！")));
            if (!oldClasses.getCreater().equals(currentUserId))
                throw new AuthException("该班级的创建人是:"
                        .concat(oldClasses.getCreater())
                        .concat(",你(")
                        .concat(currentUserId)
                        .concat(")无权修改！"));
            classesDao.deleteById(id);
            userClassesDao.deleteAllByClassId(id);
            classesProcessDao.deleteByToClasses(id);
        }
        for (int i = 0, length = classesIds.size(); i < length; i++) {//最后才去取消
            cancelTimingJob(classesIds.get(i), "openClasses", 0);//取消原有定时任务
        }
    }

    //班级到了开班截止时间要执行的事情
    @Transactional
    public void classesOnTimeWork(String id) {
        Classes oldClasses = classesDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该班级("
                .concat(id)
                .concat(")不存在！")));
        Integer memberCount = userClassesDao.countAllByClassId(id);
        ClassesProcess process = classesProcessDao.findByToClasses(id);
        if (memberCount >= process.getMinMemberCount()) {//如果目前班级人数大于等于规划的最小人数的话
            String oldCreater = oldClasses.getCreater();
            classesDao.updateCreater(process.getToDirector(), id);//将此班级的创建人改为预定的主任
            classesDao.updateIsAutomatic(false, id);//更新班级的判断位，这样就不会出现在用户选择班级的列表上
            noticeDirectorManageClasses(process.getToDirector(), oldClasses.getName());//发送任务通知主任该班级归他管
            noticeAdminClassesCreaterIsChange(process.getToDirector(), oldCreater, oldClasses.getName());//发送任务通知管理员班级开班流程结束了
        } else//通知管理员说该班级的开班流程已经结束了,但是不具备开班条件
            noticeAdminClassesOpenFail(oldClasses.getCreater(), oldClasses.getName(), "人数不足（"
                    .concat(memberCount.toString())
                    .concat("/")
                    .concat(process.getMinMemberCount().toString())
                    .concat(")"));
    }

    @Transactional
    //管理员直接手动完成班级流程，即不按时间规划，直接完成开班
    public void manualOverClassesProcess(String classes, String currentUserId) {
        Classes oldClasses = classesDao.findById(classes).orElseThrow(() -> new IllegalArgumentException("该班级("
                .concat(classes)
                .concat(")不存在！")));
        if (!oldClasses.getCreater().equals(currentUserId))
            throw new AuthException("该班级的创建人是:"
                    .concat(oldClasses.getCreater())
                    .concat(",你(")
                    .concat(currentUserId)
                    .concat(")无权修改！"));
        ClassesProcess classesProcess = classesProcessDao.findByToClasses(classes);
        classesDao.updateCreater(classesProcess.getToDirector(), classes);
        classesDao.updateIsAutomatic(false, classes);//更新班级的判断位，这样就不会出现在用户选择班级的列表上
        noticeDirectorManageClasses(classesProcess.getToDirector(), oldClasses.getName());//发送任务通知主任该班级归他管
        cancelTimingJob(classes, "openClasses", 0);//取消原有定时任务
    }

    //用户获取可以加入的班级列表
    @Transactional(readOnly = true)
    public List<ClassesStoreListDto> getClassesStoreList(String currentUserId) {
        LocalDateTime now = LocalDateTime.now();
        List<ClassesProcessView> viewList = classesProcessViewDao.findAllByIsAutomaticAndEnterBeginTimeBeforeAndEnterEndTimeAfter(true, now, now);
        List<ClassesStoreListDto> result = new LinkedList<>();
        UserClass example = new UserClass(null, null, currentUserId);
        for (int i = 0, length = viewList.size(); i < length; i++) {
            String classesId = viewList.get(i).getId();
            example.setClassId(classesId);
            boolean isHadIn = userClassesDao.exists(Example.of(example));
            int nowCount = userClassesDao.countAllByClassId(classesId);
            result.add(new ClassesStoreListDto(classesId, viewList.get(i).getName(), viewList.get(i).getDescribe(), viewList.get(i).getStage(), viewList.get(i).getEnterBeginTime(), viewList.get(i).getEnterEndTime(), nowCount, viewList.get(i).getMinMemberCount(), viewList.get(i).getMaxMemberCount(), isHadIn));
        }
        return result;
    }

    //用户加入班级之后的操作
    @Transactional
    public Integer joinClasses(String currentUserId, String classesId) {
        int nowCount = userClassesDao.countAllByClassId(classesId);
        ClassesProcess process = classesProcessDao.findByToClasses(classesId);
        if (nowCount >= process.getMaxMemberCount())
            return -1;
        else {
            userClassesDao.save(new UserClass(UuidUtil.get32Uuid(), classesId, currentUserId));
            nowCount++;
            if (nowCount >= process.getMaxMemberCount()) {
                String oldCreater = classesDao.getCreater(classesId);
                String name = classesDao.getName(classesId);
                classesDao.updateCreater(process.getToDirector(), classesId);//将此班级的创建人改为预定的主任
                classesDao.updateIsAutomatic(false, classesId);//更新班级的判断位，这样就不会出现在用户选择班级的列表上
                noticeDirectorManageClasses(process.getToDirector(), name);//发送任务通知主任该班级归他管
                noticeAdminClassesCreaterIsChange(process.getToDirector(), oldCreater, name);//发送任务通知管理员班级开班流程结束了
                cancelTimingJob(classesId, "openClasses", 0);//取消原有定时任务
            }
            return nowCount;
        }
    }

    //用户退出报名班级之后的操作
    @Transactional
    public Integer exitClasses(String currentUserId, String classesId) {
        int nowCount = userClassesDao.countAllByClassId(classesId);
        ClassesProcess process = classesProcessDao.findByToClasses(classesId);
        if (nowCount >= process.getMaxMemberCount())
            return -1;
        else {
            UserClass example = new UserClass(null, classesId, currentUserId);//删除用户班级关系
            userClassesDao.delete(userClassesDao.findOne(Example.of(example)).orElseThrow(() -> new IllegalArgumentException("该用户班级关系(classes:".concat(classesId).concat(",user:").concat(currentUserId).concat("不存在！"))));
            return --nowCount;
        }
    }

    //通过组Id获取班级名字
    public String getClassNameByGroupId(String groupId) {
        List<String> classesId = groupClassesDao.findClassIdByGroupId(groupId);
        return classesId.size() > 0 ? classesDao.getName(classesId.get(0)) : null;
    }

    //创建到了开班截止时间的定时任务
    private void createOpenClassesJob(ClassesAndProcessInDto classesAndProcessInDto) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<JobInDtoBase> httpEntity = new HttpEntity<>(new JobInDtoBase(classesAndProcessInDto.getId(), "openClasses", "在"
                .concat(classesAndProcessInDto.getProcess().getEnterEndTime().toString())
                .concat("时终止班级(")
                .concat(classesAndProcessInDto.getId())
                .concat(")的报名,并把班级的创建人改为")
                .concat(classesAndProcessInDto.getProcess().getToDirector()), classesAndProcessInDto.getProcess().getEnterEndTime()), headers);
        restTemplate.postForObject(ServiceName.QUERTZ_SERVICE.getServiceName().concat("/openClasses"), httpEntity, Object.class);//创建到了班级报名截止时间之后的定时任务
    }

    //将查出来的班级（id，name）装进Dto
    private List<TreeDto> objectToClassesDto(List<Object[]> classList) {
        List<TreeDto> dtos = new ArrayList<>(classList.size());
        for (int i = 0, length = classList.size(); i < length; i++) {
            int childrenCount = groupClassesDao.countByClassId((String) classList.get(i)[0]);
            dtos.add(new TreeDto((String) classList.get(i)[0], "root", 0, childrenCount, (String) classList.get(i)[1]));
        }
        return dtos;
    }

    //刷新某人的权限版本号
    private void refreshUserAuthVersionCache(String userId) {
        AuthVersion av = authVersionDao.findById(userId).orElse(new AuthVersion(userId, 0));
        av.setVersion(av.getVersion() + 1);
        authVersionDao.save(av);
        redis.set(userId, av.getVersion(), redis.EXPIRETIME);
    }

    //将某个人的一个角色替换成另一个角色
    private void replaceUserRole(String userId, String newRole) {
        userRoleDao.deleteAllByUserId(userId);//就要去把他的角色全部删除
        userRoleDao.save(new UserRole(userId, roleDao.getIdByName("ROLE_BASE")));//基础角色不能删
        userRoleDao.save(new UserRole(userId, roleDao.getIdByName(newRole)));//然后在添加新的角色信息
    }

    //取消班级原有的定时任务
    private void cancelTimingJob(String classesId, String key, int type) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<JobkeyDto> httpEntity = new HttpEntity<>(new JobkeyDto(key, classesId, type), headers);
        restTemplate.postForEntity(ServiceName.BUS_SERVICE.getServiceName().concat("/message/quertz"), httpEntity, String.class);//取消原有定时任务
    }

    //向任务服务发送任务
    private void sendTask(TaskInDto taskInDto) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<TaskInDto> httpEntity = new HttpEntity<>(taskInDto, headers);
        restTemplate.postForObject(ServiceName.TASK_SERVICE.getServiceName(), httpEntity, Object.class);
    }

    //通知某个主任说该班级归他管
    private void noticeDirectorManageClasses(String director, String classesName) {
        Task task = Task.builder()
                .id(UuidUtil.get32Uuid())
                .name("管理班级")
                .responsible(director)
                .isAttachment(0)
                .isGroup(0)
                .status(1)
                .type(4)
                .priority(0)
                .description("从现在起由你负责班级("
                        .concat(classesName)
                        .concat(")的管理,详情可查看班级详情"))
                .build();
        List<String> receiver = new ArrayList<>(1);
        receiver.add(director);
        sendTask(new TaskInDto(task, receiver));//发送任务通知主任该班级归他管
    }

    //通知管理员说说该班级已经交给谁来管理了
    private void noticeAdminClassesCreaterIsChange(String director, String admin, String classesName) {
        Task task = Task.builder()
                .id(UuidUtil.get32Uuid())
                .name("开班结束")
                .responsible(admin)
                .isAttachment(0)
                .isGroup(0)
                .status(1)
                .type(4)
                .priority(0)
                .description("班级("
                        .concat(classesName)
                        .concat(")的报名已经截止,管理权已移交给")
                        .concat(userDao.getRealName(director))
                        .concat("管理"))
                .build();
        List<String> receiver = new ArrayList<>(1);
        receiver.add(admin);
        sendTask(new TaskInDto(task, receiver));//发送任务通知管理员班级开班结束
    }

    //通知管理员说该班级的开班流程已经结束了,但是不具备开班条件
    private void noticeAdminClassesOpenFail(String admin, String classesName, String reason) {
        Task task = Task.builder()
                .id(UuidUtil.get32Uuid())
                .name("开班条件不符")
                .responsible(admin)
                .isAttachment(0)
                .isGroup(0)
                .status(1)
                .type(4)
                .priority(0)
                .description("班级("
                        .concat(classesName)
                        .concat(")的报名已经截止,但不具备开班条件,原因:")
                        .concat(reason))
                .build();
        List<String> receiver = new ArrayList<>(1);
        receiver.add(admin);
        sendTask(new TaskInDto(task, receiver));//发送任务通知管理员班级开班结束,但是不具备开班条件
    }
}
